package com.coldlz.mmp.proxy;

import io.netty.channel.Channel;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class UserContext {
    private static final AtomicInteger SESSION_ID_GENERATOR = new AtomicInteger(0);

    @Getter
    private final int sessionId = SESSION_ID_GENERATOR.incrementAndGet();
    @Getter
    private final boolean directForward;
    @Getter
    private final List<Object> interceptors;
    @Getter
    private final ProxyInfo proxyInfo = new ProxyInfo();

    private final Channel clientChannel;

    @Setter
    @Getter
    private RecordInterceptor recordInterceptor;
    private Channel remoteChannel;


    public UserContext(List<Object> interceptors, boolean directForward, Channel clientChannel) {
        this.interceptors = interceptors != null ?
                Collections.unmodifiableList(interceptors)
                : Collections.emptyList();
        this.directForward = directForward;
        this.clientChannel = clientChannel;
    }

    public Channel getClientChannel() {
        if (clientChannel != null) {
            return clientChannel;
        } else {
            throw new ProxyException("clientChannel is null");
        }
    }

    public void setRemoteChannel(Channel remoteChannel) {
        if (this.remoteChannel == null) {
            this.remoteChannel = remoteChannel;
        } else {
            throw new ProxyException("remoteChannel is not null");
        }
    }

    public Channel getRemoteChannel() {
        if (remoteChannel != null) {
            return remoteChannel;
        } else {
            throw new ProxyException("remoteChannel is null");
        }
    }

    public void close() {
        String localAddress = clientChannel != null ? clientChannel.remoteAddress().toString() : "null";
        String remoteAddress = remoteChannel != null ? remoteChannel.remoteAddress().toString() : "null";
        try {
            RemoteClient client = RemoteClientFactory.getClient(this);
            if (client != null) {
                RemoteClientFactory.removeAndDestroy(client);
            }
        } catch (Exception e) {
            log.warn("关闭 RemoteClient 异常", e);
        }
        try {
            if (clientChannel != null) {
                clientChannel.close();
            }
        } catch (Exception e) {
            log.warn("关闭 clientChannel 异常", e);
        }
        try {
            if (remoteChannel != null) {
                remoteChannel.close();
            }
        } catch (Exception e) {
            log.warn("关闭 remoteChannel 异常", e);
        }

        ThreadPoolsUtil.cachedThreadPool.execute(() -> {
            for (Object item : this.interceptors) {
                if (item instanceof Interceptor interceptor) {
                    try {
                        interceptor.closeAfterCallback();
                    } catch (Exception e) {
                        log.warn("interceptor.closeAfterCallback error {}", interceptor.getClass(), e);
                    }
                }
            }
        });
        log.info("<====关闭 UserContext 结束,localAddress={} remoteAddress={}", localAddress, remoteAddress);
    }
}
